package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.entity.BizException;
import cn.stylefeng.guns.modular.gridsystem.entity.BizExceptionLog;
import cn.stylefeng.guns.modular.gridsystem.entity.BizFaultModel;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizExceptionMapper;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizExceptionLogParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizExceptionParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizExceptionResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.DeviceExceptionInfoResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.ExceptionCountDataResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.ExceptionHandleDataResult;
import cn.stylefeng.guns.modular.gridsystem.mqtt.result.FaultHistory;
import cn.stylefeng.guns.modular.gridsystem.service.BizExceptionLogService;
import cn.stylefeng.guns.modular.gridsystem.service.BizExceptionService;
import cn.stylefeng.guns.modular.gridsystem.service.BizFaultModelService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * 故障表 服务实现类
 *
 * @author ssy
 * @date 2021/09/14 11:47
 */
@Service
public class BizExceptionServiceImpl extends ServiceImpl<BizExceptionMapper, BizException> implements BizExceptionService {

    @Resource
    private BizExceptionLogService bizExceptionLogService;
    @Resource
    private BizFaultModelService faultModelService;

    /**
     * 分页查询故障表
     *
     * @param bizExceptionParam
     * @return
     */
    @Override
    public PageResult<BizException> page(BizExceptionParam bizExceptionParam) {
        // 构造条件
        LambdaQueryWrapper<BizException> queryWrapper = new LambdaQueryWrapper<>();
        // 查询分页结果
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    /**
     * 查询所有故障表
     *
     * @param bizExceptionParam
     * @return
     */
    @Override
    public List<BizException> list(BizExceptionParam bizExceptionParam) {
        // 构造条件
        LambdaQueryWrapper<BizException> queryWrapper = new LambdaQueryWrapper<>();
        if (bizExceptionParam != null && ObjectUtil.isNotEmpty(bizExceptionParam.getDeviceId())) {
            queryWrapper.eq(BizException::getDeviceId, bizExceptionParam.getDeviceId());
        }
        return this.list(queryWrapper);
    }

    /**
     * 添加故障表
     *
     * @param bizExceptionParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BizExceptionParam bizExceptionParam) {
        // 将dto转为实体
        BizException bizException = new BizException();
        BeanUtil.copyProperties(bizExceptionParam, bizException);
        this.save(bizException);
    }

    /**
     * 新增故障返回id
     *
     * @param bizExceptionParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addAndReturnId(BizExceptionParam bizExceptionParam) {
        this.baseMapper.insertAndReturnId(bizExceptionParam);
        return bizExceptionParam.getId();
    }

    /**
     * 分页查询故障表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<BizExceptionResult> pageList(BizExceptionParam param) {
        if (ObjectUtil.isEmpty(param.getStationId())) {
            param.setStationId(0);
        }
        Page<BizExceptionResult> page = this.baseMapper.page(PageFactory.defaultPage(), param);
        return new PageResult<>(page);
    }

    /**
     * 删除故障和子故障
     *
     * @param bizExceptionParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizExceptionParam bizExceptionParam) {
        //获取对应的子故障删除
        final LambdaQueryWrapper<BizExceptionLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizExceptionLog::getExceptionId, bizExceptionParam.getId());
        List<BizExceptionLog> list = bizExceptionLogService.list(queryWrapper);
        for (BizExceptionLog exceptionLog : list) {
            BizExceptionLogParam bizExceptionLogParam = new BizExceptionLogParam();
            // 请求参数转化为实体
            BeanUtil.copyProperties(exceptionLog, bizExceptionLogParam);
            bizExceptionLogService.delete(bizExceptionLogParam);
        }

        this.removeById(bizExceptionParam.getId());
    }

    /**
     * 根据id修改故障信息
     *
     * @param bizExceptionParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(BizExceptionParam bizExceptionParam) {
        // 根据id查询实体
        BizException bizException = this.queryBizException(bizExceptionParam);
        // 请求参数转化为实体
        BeanUtil.copyProperties(bizExceptionParam, bizException);
        this.updateById(bizException);
    }

    /**
     * 查看详情故障表
     *
     * @param bizExceptionParam
     * @return
     */
    @Override
    public BizException detail(BizExceptionParam bizExceptionParam) {
        return this.queryBizException(bizExceptionParam);
    }

    /**
     * 修改状态（字典 0正常 1停用 2删除）
     *
     * @param bizExceptionParam
     */
    @Override
    public void changeStatus(BizExceptionParam bizExceptionParam) {
        Integer id = bizExceptionParam.getId();
        Integer status = bizExceptionParam.getStatus();
        // 更新枚举，更新只能更新未删除状态的
        LambdaUpdateWrapper<BizException> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .eq(BizException::getId, id)
                .set(BizException::getStatus, status)
                .set(BizException::getUpdateTime, DateUtil.date());
        this.update(updateWrapper);
    }

    /**
     * 查询设备最新一条未处理故障
     * @param deviceId
     * @return
     */
    @Override
    public Map<String, Object> getNewfaultFile(Integer deviceId) {
        QueryWrapper<BizException> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_id", deviceId);
        queryWrapper.eq("status", 0);
        queryWrapper.orderByDesc("created_at");
        queryWrapper.last("limit 1");
        BizException bizException = this.getOne(queryWrapper);
        if (ObjectUtil.isNotNull(bizException)) {
            Integer id = bizException.getId();
            QueryWrapper<BizExceptionLog> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("exception_id", id);
            queryWrapper1.orderByDesc("created_at");
            queryWrapper1.last("limit 1");
            Map<String, Object> one = bizExceptionLogService.getMap(queryWrapper1);
            String errorName = bizException.getErrorName();
            QueryWrapper<BizFaultModel> faultModelQueryWrapper = new QueryWrapper<>();
            faultModelQueryWrapper.eq("fault_name", errorName);
            faultModelQueryWrapper.last("limit 1");
            BizFaultModel faultModel = faultModelService.getOne(faultModelQueryWrapper);
            if (ObjectUtil.isNotNull(faultModel)) {
                String faultFile = faultModel.getModelFile();
                one.put("faultFile", faultFile);
                if (ObjectUtil.isNotEmpty(faultModel.getFaultGif())) {
                    one.put("faultGif", faultModel.getFaultGif());
                    one.put("isfaultGif", true);
                    one.put("errorName", errorName);
                }
            }
            return one;
        }
        return null;
    }

    /**
     * 查询设备未处理故障
     * @param deviceId
     * @return
     */
    @Override
    public Set<String> getNewfaultList(Integer deviceId) {
        QueryWrapper<BizException> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_id", deviceId);
        queryWrapper.eq("DATE_FORMAT(created_at,'%Y-%m-%d')", DateUtil.today());
        queryWrapper.eq("status", 0);
        queryWrapper.orderByDesc("created_at");
        queryWrapper.last("limit 1");
        BizException bizException = this.getOne(queryWrapper);
        if (bizException != null) {
            Integer id = bizException.getId();
            BizExceptionLogParam exceptionLogParam = new BizExceptionLogParam();
            exceptionLogParam.setId(id);
            List<BizExceptionLog> list = bizExceptionLogService.list(exceptionLogParam);
            Set<String> channels = new HashSet<>();
            for (BizExceptionLog bizExceptionLog : list) {
                String gatewayChannel = bizExceptionLog.getGatewayChannel();
                channels.add(gatewayChannel);
            }
            return channels;
        }
        return null;
    }

    /**
     * 查询最新一条
     *
     * @param bizExceptionParam 故障表
     * @return BizException
     */
    @Override
    public BizException oneByErrorNameAndToday(BizExceptionParam bizExceptionParam) {
        QueryWrapper<BizException> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_id", bizExceptionParam.getDeviceId());
        queryWrapper.eq("error_name", bizExceptionParam.getErrorName());
        queryWrapper.eq("gateway_code", bizExceptionParam.getGatewayCode());
        queryWrapper.last("limit 1");
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * 获取故障表
     *
     * @author ssy
     * @since 2021/09/14 11:47
     */
    private BizException queryBizException(BizExceptionParam bizExceptionParam) {
        return this.getById(bizExceptionParam.getId());
    }

    /**
     * 获取处理状态的数量
     *
     * @param deviceId
     * @return
     */
    public Map<String, Long> countStatus(Integer deviceId) {
        return this.baseMapper.countStatus(deviceId);
    }

    /**
     * 当年月度故障数量
     *
     * @param stationId
     * @return
     */
    @Override
    public Map<String, Object> getErrorCountByMonth(Integer stationId) {
        int[] errCounts = new int[12];
        int[] processedCounts = new int[12];
        int[] unprocessedCounts = new int[12];
        int allErrCount = 0;
        int allProcessedCount = 0;
        List<ExceptionCountDataResult> resultList = baseMapper.getErrorCountByMonth(stationId);
        for (ExceptionCountDataResult result : resultList) {
            int index = result.getMonthDay() - 1;
            allErrCount += result.getErrCount();
            allProcessedCount += result.getProcessedNumber();
            errCounts[index] = result.getErrCount();
            processedCounts[index] = result.getProcessedNumber();
            unprocessedCounts[index] = result.getUnprocessedNumber();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("errList", errCounts);
        map.put("processedList", processedCounts);
        map.put("unprocessedList", unprocessedCounts);
        map.put("allErrCount", allErrCount);
        map.put("allProcessedCount", allProcessedCount);
        return map;
    }

    @Override
    public List<ExceptionCountDataResult> getErrorCountByMonthList(Integer stationId) {
        return this.baseMapper.getErrorCountByMonth(stationId);
    }

    /**
     * 查询异常的具体信息
     *
     * @param page
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public PageResult<FaultHistory> queryFaultHistory(Page page, String startTime, String endTime) {
        // 查询分页结果
        return new PageResult<>(this.baseMapper.faultHistoryPage(page, startTime, endTime));
    }

    /**
     * 根据异常获取异常信息
     *
     * @param stationId
     * @param deviceId
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<BizExceptionResult> getDeviceExceptionList(Integer stationId, Integer deviceId, String startTime, String endTime) {
        return this.baseMapper.getDeviceExceptionList(stationId, deviceId, startTime, endTime);
    }

    /**
     * 获取站点中已处理未处理故障数量
     *
     * @param stationId
     * @return
     */
    @Override
    public ExceptionHandleDataResult getExceptionHandleInfo(Integer stationId) {
        return this.baseMapper.getExceptionHandleInfo(stationId);
    }

    /**
     * 获取设备异常信息列表
     *
     * @param deviceId
     * @return
     */
    @Override
    public PageResult<DeviceExceptionInfoResult> getDeviceExceptionInfoList(Integer deviceId) {
        Page<DeviceExceptionInfoResult> page = this.baseMapper.getDeviceExceptionInfoList(PageFactory.defaultPage(), deviceId);
        return new PageResult<>(page);
    }

    /**
     * 定时结束警告声发
     *
     * @param id
     */
    public void stopAndStart(Integer id) {
        Timer timer = new Timer();
        log.warn("定时声发计时开始");
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                LambdaQueryWrapper<BizException> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(BizException::getId, id);
                BizException bizExceptions = baseMapper.selectOne(queryWrapper);
                if (ObjectUtil.isNotEmpty(bizExceptions)) {
                    bizExceptions.setStatus(1);
                    baseMapper.updateById(bizExceptions);
                }
            }
        };
        timer.schedule(task, 60000);
        log.warn("定时声发计时结束");
    }

    /**
     * 查询故障数量
     * @param deviceId
     * @return
     */
    @Override
    public List<Map<String, Object>> getExceptionInfo(Integer deviceId) {
        QueryWrapper<BizException> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("count(*) as value", "error_name as name");
        queryWrapper.eq("device_id", deviceId);
        queryWrapper.groupBy("error_name");
        return this.listMaps(queryWrapper);
    }

    /**
     * 查询网关下的故障数量
     * @param deviceCode
     * @return
     */
    @Override
    public Integer getGatewayExceptionStatus(String deviceCode) {
        LambdaQueryWrapper<BizException> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizException::getGatewayCode, deviceCode)
                .eq(BizException::getStatus, 0);
        List<BizException> list = this.list(queryWrapper);
        return list.size();
    }

}
